package com.bestcem.xm.common.core.sql.calculator;

import com.bestcem.xm.common.core.constant.Constants;
import com.bestcem.xm.common.core.sql.ConditionConstant;
import com.bestcem.xm.common.core.sql.ConditionGrammarException;
import com.bestcem.xm.common.core.sql.ConditionProxy;
import com.bestcem.xm.common.core.sql.ParamsProxy;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

/**
 * @author dc.wang <dc.wang@idiaoyan.com>
 * @version V1.0
 * @description range condition calculator
 * @date 2021/5/26
 */
@Slf4j
public class RangeConditionCalculator extends ConditionCalculator{
    public RangeConditionCalculator(ConditionProxy conditionProxy, ParamsProxy paramsProxy) {
        super(conditionProxy, paramsProxy);
    }

    @Override
    protected List<String> getSupportedDataTypes() {
        return Arrays.asList(ConditionConstant.FieldTypes.DATETIME,
                ConditionConstant.FieldTypes.NUMBER);
    }

    @Override
    protected String getOperator() {
        return ConditionConstant.Operators.RANGE;
    }

    @Override
    protected boolean onCalculate() {
        List<Object> conditionValues = this.conditionProxy.listValues();
        Object paramValue = this.getParamValue();

        if (conditionValues.size() != Constants.TWO) {
            throw new ConditionGrammarException("condition.value array size should equal 2 for operator $range");
        }
        if (paramValue == null) {
            return this.getDefaultResult();
        }

        // 避免多次类型转化、集合下标查询
        Comparable<Object> comparableParamValue = (Comparable) paramValue;
        Object conditionValueLeft = conditionValues.get(0);
        Object conditionValueRight = conditionValues.get(1);
        if (conditionValueLeft == null || conditionValueRight == null) {
            String msg = String.format("condition.value missing for $range, left: %s, right: %s",
                    conditionValueLeft, conditionValueRight);
            throw new ConditionGrammarException(msg);
        }

        boolean leftMatch = comparableParamValue.compareTo(conditionValueLeft) > 0;
        // 如果不大于左边界，且条件左边界关闭，校验左边界
        if(!leftMatch && !this.conditionProxy.isLeftOpen()){
            leftMatch = comparableParamValue.compareTo(conditionValueLeft) == 0;
        }

        boolean rightMatch = comparableParamValue.compareTo(conditionValueRight) < 0;
        // 如果不大于右边界，且条件左边界关闭，校验左边界
        if(!rightMatch && !this.conditionProxy.isRightOpen()){
            rightMatch = comparableParamValue.compareTo(conditionValueRight) == 0;
        }

        return leftMatch && rightMatch;
    }
}